home *** CD-ROM | disk | FTP | other *** search
- /*
- * hfsutils - tools for reading and writing Macintosh HFS volumes
- * Copyright (C) 1996, 1997 Robert Leslie
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- #include <mconfig.h>
- #include <strdefs.h>
- #include <stdxlib.h>
- #include <errno.h>
- #include <unixstd.h>
- #include <fcntl.h>
-
- #include "internal.h"
- #include "data.h"
- #include "block.h"
- #include "low.h"
- #include "file.h"
-
- /*
- * NAME: low->lockvol()
- * DESCRIPTION: prevent destructive simultaneous access
- */
- int l_lockvol(vol)
- hfsvol *vol;
- {
- # ifndef NODEVLOCKS
-
- struct flock lock;
-
- lock.l_type = (vol->flags & HFS_READONLY) ? F_RDLCK : F_WRLCK;
- lock.l_start = 0;
- lock.l_whence = SEEK_SET;
- lock.l_len = 0;
-
- if (fcntl(vol->fd, F_SETLK, &lock) < 0)
- {
- ERROR(errno, "unable to obtain lock for device");
- return -1;
- }
-
- # endif
-
- return 0;
- }
-
- /*
- * NAME: low->readblock0()
- * DESCRIPTION: read the first sector and get bearings
- */
- int l_readblock0(vol)
- hfsvol *vol;
- {
- block b;
- unsigned char *ptr = b;
- Block0 rec;
-
- if (b_readlb(vol, 0, &b) < 0)
- return -1;
-
- d_fetchw(&ptr, &rec.sbSig);
- d_fetchw(&ptr, &rec.sbBlkSize);
- d_fetchl(&ptr, &rec.sbBlkCount);
- d_fetchw(&ptr, &rec.sbDevType);
- d_fetchw(&ptr, &rec.sbDevId);
- d_fetchl(&ptr, &rec.sbData);
- d_fetchw(&ptr, &rec.sbDrvrCount);
- d_fetchl(&ptr, &rec.ddBlock);
- d_fetchw(&ptr, &rec.ddSize);
- d_fetchw(&ptr, &rec.ddType);
-
- switch (rec.sbSig)
- {
- case 0x4552: /* block device with a partition table */
- {
- if (rec.sbBlkSize != HFS_BLOCKSZ)
- {
- ERROR(EINVAL, "unsupported block size");
- return -1;
- }
-
- vol->vlen = rec.sbBlkCount;
-
- if (l_readpm(vol) < 0)
- return -1;
- }
- break;
-
- case 0x4c4b: /* bootable floppy */
- vol->pnum = 0;
- break;
-
- default: /* non-bootable floppy or something else */
-
- /* some miscreant media may also be partitioned;
- we attempt to read a partition map, but ignore any failure */
-
- if (l_readpm(vol) < 0)
- vol->pnum = 0;
- }
-
- return 0;
- }
-
- /*
- * NAME: low->readpm()
- * DESCRIPTION: read the partition map and locate an HFS volume
- */
- int l_readpm(vol)
- hfsvol *vol;
- {
- block b;
- unsigned char *ptr;
- Partition map;
- unsigned long bnum;
- int pnum;
-
- bnum = 1;
- pnum = vol->pnum;
-
- while (1)
- {
- if (b_readlb(vol, bnum, &b) < 0)
- return -1;
-
- ptr = b;
-
- d_fetchw(&ptr, &map.pmSig);
- d_fetchw(&ptr, &map.pmSigPad);
- d_fetchl(&ptr, &map.pmMapBlkCnt);
- d_fetchl(&ptr, &map.pmPyPartStart);
- d_fetchl(&ptr, &map.pmPartBlkCnt);
-
- memcpy(map.pmPartName, ptr, 32);
- map.pmPartName[32] = 0;
- ptr += 32;
-
- memcpy(map.pmParType, ptr, 32);
- map.pmParType[32] = 0;
- ptr += 32;
-
- d_fetchl(&ptr, &map.pmLgDataStart);
- d_fetchl(&ptr, &map.pmDataCnt);
- d_fetchl(&ptr, &map.pmPartStatus);
- d_fetchl(&ptr, &map.pmLgBootStart);
- d_fetchl(&ptr, &map.pmBootSize);
- d_fetchl(&ptr, &map.pmBootAddr);
- d_fetchl(&ptr, &map.pmBootAddr2);
- d_fetchl(&ptr, &map.pmBootEntry);
- d_fetchl(&ptr, &map.pmBootEntry2);
- d_fetchl(&ptr, &map.pmBootCksum);
-
- memcpy(map.pmProcessor, ptr, 16);
- map.pmProcessor[16] = 0;
- ptr += 16;
-
- if (map.pmSig == 0x5453)
- {
- /* old partition map sig */
-
- ERROR(EINVAL, "unsupported partition map signature");
- return -1;
- }
-
- if (map.pmSig != 0x504d)
- {
- ERROR(EINVAL, "bad partition map");
- return -1;
- }
-
- if (strcmp((char *) map.pmParType, "Apple_HFS") == 0 && --pnum == 0)
- {
- if (map.pmLgDataStart != 0)
- {
- ERROR(EINVAL, "unsupported start of partition logical data");
- return -1;
- }
-
- vol->vstart = map.pmPyPartStart;
- vol->vlen = map.pmPartBlkCnt;
-
- return 0;
- }
-
- if (bnum >= map.pmMapBlkCnt)
- {
- ERROR(EINVAL, "can't find HFS partition");
- return -1;
- }
-
- ++bnum;
- }
- }
-
- /*
- * NAME: low->readmdb()
- * DESCRIPTION: read the master directory block into memory
- */
- int l_readmdb(vol)
- hfsvol *vol;
- {
- block b;
- unsigned char *ptr = b;
- MDB *mdb = &vol->mdb;
- hfsfile *ext = &vol->ext.f;
- hfsfile *cat = &vol->cat.f;
- int i;
-
- if (b_readlb(vol, 2, &b) < 0)
- return -1;
-
- d_fetchw(&ptr, &mdb->drSigWord);
- d_fetchl(&ptr, &mdb->drCrDate);
- d_fetchl(&ptr, &mdb->drLsMod);
- d_fetchw(&ptr, &mdb->drAtrb);
- d_fetchw(&ptr, (short *) &mdb->drNmFls);
- d_fetchw(&ptr, (short *) &mdb->drVBMSt);
- d_fetchw(&ptr, (short *) &mdb->drAllocPtr);
- d_fetchw(&ptr, (short *) &mdb->drNmAlBlks);
- d_fetchl(&ptr, (long *) &mdb->drAlBlkSiz);
- d_fetchl(&ptr, (long *) &mdb->drClpSiz);
- d_fetchw(&ptr, (short *) &mdb->drAlBlSt);
- d_fetchl(&ptr, &mdb->drNxtCNID);
- d_fetchw(&ptr, (short *) &mdb->drFreeBks);
-
- d_fetchs(&ptr, mdb->drVN, sizeof(mdb->drVN));
-
- if (ptr - b != 64)
- abort();
-
- d_fetchl(&ptr, &mdb->drVolBkUp);
- d_fetchw(&ptr, &mdb->drVSeqNum);
- d_fetchl(&ptr, (long *) &mdb->drWrCnt);
- d_fetchl(&ptr, (long *) &mdb->drXTClpSiz);
- d_fetchl(&ptr, (long *) &mdb->drCTClpSiz);
- d_fetchw(&ptr, (short *) &mdb->drNmRtDirs);
- d_fetchl(&ptr, (long *) &mdb->drFilCnt);
- d_fetchl(&ptr, (long *) &mdb->drDirCnt);
-
- for (i = 0; i < 8; ++i)
- d_fetchl(&ptr, &mdb->drFndrInfo[i]);
-
- if (ptr - b != 124)
- abort();
-
- d_fetchw(&ptr, (short *) &mdb->drVCSize);
- d_fetchw(&ptr, (short *) &mdb->drVBMCSize);
- d_fetchw(&ptr, (short *) &mdb->drCtlCSize);
-
- d_fetchl(&ptr, (long *) &mdb->drXTFlSize);
-
- for (i = 0; i < 3; ++i)
- {
- d_fetchw(&ptr, (short *) &mdb->drXTExtRec[i].xdrStABN);
- d_fetchw(&ptr, (short *) &mdb->drXTExtRec[i].xdrNumABlks);
- }
-
- if (ptr - b != 146)
- abort();
-
- d_fetchl(&ptr, (long *) &mdb->drCTFlSize);
-
- for (i = 0; i < 3; ++i)
- {
- d_fetchw(&ptr, (short *) &mdb->drCTExtRec[i].xdrStABN);
- d_fetchw(&ptr, (short *) &mdb->drCTExtRec[i].xdrNumABlks);
- }
-
- if (ptr - b != 162)
- abort();
-
- vol->lpa = mdb->drAlBlkSiz / HFS_BLOCKSZ;
-
- /* extents pseudo-file structs */
-
- ext->vol = vol;
- ext->parid = 0;
- strcpy(ext->name, "extents overflow");
-
- ext->cat.cdrType = cdrFilRec;
- /* ext->cat.cdrResrv2 */
- ext->cat.u.fil.filFlags = 0;
- ext->cat.u.fil.filTyp = 0;
- /* ext->cat.u.fil.filUsrWds */
- ext->cat.u.fil.filFlNum = HFS_CNID_EXT;
- ext->cat.u.fil.filStBlk = mdb->drXTExtRec[0].xdrStABN;
- ext->cat.u.fil.filLgLen = mdb->drXTFlSize;
- ext->cat.u.fil.filPyLen = mdb->drXTFlSize;
- ext->cat.u.fil.filRStBlk = 0;
- ext->cat.u.fil.filRLgLen = 0;
- ext->cat.u.fil.filRPyLen = 0;
- ext->cat.u.fil.filCrDat = mdb->drCrDate;
- ext->cat.u.fil.filMdDat = mdb->drLsMod;
- ext->cat.u.fil.filBkDat = 0;
- /* ext->cat.u.fil.filFndrInfo */
- ext->cat.u.fil.filClpSize = 0;
-
- memcpy(ext->cat.u.fil.filExtRec, mdb->drXTExtRec, sizeof(ExtDataRec));
- for (i = 0; i < 3; ++i)
- {
- ext->cat.u.fil.filRExtRec[i].xdrStABN = 0;
- ext->cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
- }
- f_selectfork(ext, 0);
-
- ext->clump = mdb->drXTClpSiz;
- ext->flags = 0;
-
- ext->prev = ext->next = 0;
-
- /* catalog pseudo-file structs */
-
- cat->vol = vol;
- cat->parid = 0;
- strcpy(cat->name, "catalog");
-
- cat->cat.cdrType = cdrFilRec;
- /* cat->cat.cdrResrv2 */
- cat->cat.u.fil.filFlags = 0;
- cat->cat.u.fil.filTyp = 0;
- /* cat->cat.u.fil.filUsrWds */
- cat->cat.u.fil.filFlNum = HFS_CNID_CAT;
- cat->cat.u.fil.filStBlk = mdb->drCTExtRec[0].xdrStABN;
- cat->cat.u.fil.filLgLen = mdb->drCTFlSize;
- cat->cat.u.fil.filPyLen = mdb->drCTFlSize;
- cat->cat.u.fil.filRStBlk = 0;
- cat->cat.u.fil.filRLgLen = 0;
- cat->cat.u.fil.filRPyLen = 0;
- cat->cat.u.fil.filCrDat = mdb->drCrDate;
- cat->cat.u.fil.filMdDat = mdb->drLsMod;
- cat->cat.u.fil.filBkDat = 0;
- /* cat->cat.u.fil.filFndrInfo */
- cat->cat.u.fil.filClpSize = 0;
-
- memcpy(cat->cat.u.fil.filExtRec, mdb->drCTExtRec, sizeof(ExtDataRec));
- for (i = 0; i < 3; ++i)
- {
- cat->cat.u.fil.filRExtRec[i].xdrStABN = 0;
- cat->cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
- }
- f_selectfork(cat, 0);
-
- cat->clump = mdb->drCTClpSiz;
- cat->flags = 0;
-
- cat->prev = cat->next = 0;
-
- return 0;
- }
-
- /*
- * NAME: low->writemdb()
- * DESCRIPTION: write the master directory block to disk
- */
- int l_writemdb(vol)
- hfsvol *vol;
- {
- block b;
- unsigned char *ptr = b;
- MDB *mdb = &vol->mdb;
- hfsfile *ext = &vol->ext.f;
- hfsfile *cat = &vol->cat.f;
- int i;
-
- memset(&b, 0, sizeof(b));
-
- mdb->drXTFlSize = ext->cat.u.fil.filPyLen;
- mdb->drXTClpSiz = ext->clump;
- memcpy(mdb->drXTExtRec, ext->cat.u.fil.filExtRec, sizeof(ExtDataRec));
-
- mdb->drCTFlSize = cat->cat.u.fil.filPyLen;
- mdb->drCTClpSiz = cat->clump;
- memcpy(mdb->drCTExtRec, cat->cat.u.fil.filExtRec, sizeof(ExtDataRec));
-
- d_storew(&ptr, mdb->drSigWord);
- d_storel(&ptr, mdb->drCrDate);
- d_storel(&ptr, mdb->drLsMod);
- d_storew(&ptr, mdb->drAtrb);
- d_storew(&ptr, mdb->drNmFls);
- d_storew(&ptr, mdb->drVBMSt);
- d_storew(&ptr, mdb->drAllocPtr);
- d_storew(&ptr, mdb->drNmAlBlks);
- d_storel(&ptr, mdb->drAlBlkSiz);
- d_storel(&ptr, mdb->drClpSiz);
- d_storew(&ptr, mdb->drAlBlSt);
- d_storel(&ptr, mdb->drNxtCNID);
- d_storew(&ptr, mdb->drFreeBks);
- d_stores(&ptr, mdb->drVN, sizeof(mdb->drVN));
-
- if (ptr - b != 64)
- abort();
-
- d_storel(&ptr, mdb->drVolBkUp);
- d_storew(&ptr, mdb->drVSeqNum);
- d_storel(&ptr, mdb->drWrCnt);
- d_storel(&ptr, mdb->drXTClpSiz);
- d_storel(&ptr, mdb->drCTClpSiz);
- d_storew(&ptr, mdb->drNmRtDirs);
- d_storel(&ptr, mdb->drFilCnt);
- d_storel(&ptr, mdb->drDirCnt);
-
- for (i = 0; i < 8; ++i)
- d_storel(&ptr, mdb->drFndrInfo[i]);
-
- if (ptr - b != 124)
- abort();
-
- d_storew(&ptr, mdb->drVCSize);
- d_storew(&ptr, mdb->drVBMCSize);
- d_storew(&ptr, mdb->drCtlCSize);
- d_storel(&ptr, mdb->drXTFlSize);
-
- for (i = 0; i < 3; ++i)
- {
- d_storew(&ptr, mdb->drXTExtRec[i].xdrStABN);
- d_storew(&ptr, mdb->drXTExtRec[i].xdrNumABlks);
- }
-
- if (ptr - b != 146)
- abort();
-
- d_storel(&ptr, mdb->drCTFlSize);
-
- for (i = 0; i < 3; ++i)
- {
- d_storew(&ptr, mdb->drCTExtRec[i].xdrStABN);
- d_storew(&ptr, mdb->drCTExtRec[i].xdrNumABlks);
- }
-
- if (ptr - b != 162)
- abort();
-
- if (b_writelb(vol, 2, &b) < 0)
- return -1;
- if (vol->flags & HFS_UPDATE_ALTMDB)
- {
- #ifdef APPLE_HYB
- /* "write" alternative MDB to memory copy */
- memcpy(vol->hce->hfs_alt_mdb, &b, sizeof(b));
- #else
- if (b_writelb(vol, vol->vlen - 2, &b) < 0)
- return -1;
- #endif /* APPLE_HYB */
- }
- vol->flags &= ~(HFS_UPDATE_MDB | HFS_UPDATE_ALTMDB);
-
- return 0;
- }
-
- /*
- * NAME: low->readvbm()
- * DESCRIPTION: read the volume bit map into memory
- */
- int l_readvbm(vol)
- hfsvol *vol;
- {
- int vbmst = vol->mdb.drVBMSt;
- int vbmsz = (vol->mdb.drNmAlBlks + 4095) / 4096;
- block *bp;
-
- if (vol->mdb.drAlBlSt - vbmst < vbmsz)
- {
- ERROR(EIO, "volume bitmap collides with volume data");
- return -1;
- }
-
- bp = ALLOC(block, vbmsz);
- if (bp == 0)
- {
- ERROR(ENOMEM, 0);
- return -1;
- }
-
- vol->vbm = bp;
-
- while (vbmsz--)
- {
- if (b_readlb(vol, vbmst++, bp++) < 0)
- {
- FREE(vol->vbm);
- vol->vbm = 0;
-
- return -1;
- }
- }
-
- return 0;
- }
-
- /*
- * NAME: low->writevbm()
- * DESCRIPTION: write the volume bit map to disk
- */
- int l_writevbm(vol)
- hfsvol *vol;
- {
- int vbmst = vol->mdb.drVBMSt;
- int vbmsz = (vol->mdb.drNmAlBlks + 4095) / 4096;
- block *bp = vol->vbm;
-
- while (vbmsz--)
- {
- if (b_writelb(vol, vbmst++, bp++) < 0)
- return -1;
- }
-
- vol->flags &= ~HFS_UPDATE_VBM;
-
- return 0;
- }
-